}
});
-const TouchSwipeGesture = GObject.registerClass({
- Properties: {
- 'distance': GObject.ParamSpec.double(
- 'distance', null, null,
- GObject.ParamFlags.READWRITE,
- 0, Infinity, 0),
- 'orientation': GObject.ParamSpec.enum(
- 'orientation', null, null,
- GObject.ParamFlags.READWRITE,
- Clutter.Orientation, Clutter.Orientation.HORIZONTAL),
- },
- Signals: {
- 'begin': {param_types: [GObject.TYPE_UINT, GObject.TYPE_DOUBLE, GObject.TYPE_DOUBLE]},
- 'update': {param_types: [GObject.TYPE_UINT, GObject.TYPE_DOUBLE, GObject.TYPE_DOUBLE]},
- 'end': {param_types: [GObject.TYPE_UINT, GObject.TYPE_DOUBLE]},
- 'cancel': {param_types: [GObject.TYPE_UINT, GObject.TYPE_DOUBLE]},
- },
-}, class TouchSwipeGesture extends Clutter.GestureAction {
- _init(allowedModes, nTouchPoints, thresholdTriggerEdge) {
- super._init();
- this.set_n_touch_points(nTouchPoints);
- this.set_threshold_trigger_edge(thresholdTriggerEdge);
-
- this._allowedModes = allowedModes;
- this._distance = global.screen_height;
- this._lastPosition = 0;
- }
-
- get distance() {
- return this._distance;
- }
-
- set distance(distance) {
- if (this._distance === distance)
- return;
-
- this._distance = distance;
- this.notify('distance');
- }
-
- vfunc_gesture_prepare(actor) {
- if (!super.vfunc_gesture_prepare(actor))
- return false;
-
- if ((this._allowedModes & Main.actionMode) === 0)
- return false;
-
- let time = this.get_last_event(0).get_time();
- let [xPress, yPress] = this.get_press_coords(0);
- let [x, y] = this.get_motion_coords(0);
- const [xDelta, yDelta] = [x - xPress, y - yPress];
- const swipeOrientation = Math.abs(xDelta) > Math.abs(yDelta)
- ? Clutter.Orientation.HORIZONTAL : Clutter.Orientation.VERTICAL;
-
- if (swipeOrientation !== this.orientation)
- return false;
-
- this._lastPosition =
- this.orientation === Clutter.Orientation.VERTICAL ? y : x;
-
- this.emit('begin', time, xPress, yPress);
- return true;
- }
-
- vfunc_gesture_progress(_actor) {
- let [x, y] = this.get_motion_coords(0);
- let pos = this.orientation === Clutter.Orientation.VERTICAL ? y : x;
-
- let delta = pos - this._lastPosition;
- this._lastPosition = pos;
-
- let time = this.get_last_event(0).get_time();
-
- this.emit('update', time, -delta, this._distance);
-
- return true;
- }
-
- vfunc_gesture_end(_actor) {
- let time = this.get_last_event(0).get_time();
-
- this.emit('end', time, this._distance);
- }
-
- vfunc_gesture_cancel(_actor) {
- let time = Clutter.get_current_event_time();
-
- this.emit('cancel', time, this._distance);
- }
-});
-
const ScrollGesture = GObject.registerClass({
Properties: {
'enabled': GObject.ParamSpec.boolean(
this._history = new EventHistory();
this._reset();
+ this._panGesture = new Clutter.PanGesture({
+ min_n_points: params.allowDrag ? 1 : GESTURE_FINGER_COUNT,
+ max_n_points: params.allowDrag ? 0 : GESTURE_FINGER_COUNT,
+ });
+ this._panGesture.connect('may-recognize', () => {
+ return (this._allowedModes & Main.actionMode) !== 0;
+ });
+ this._panGesture.connect('recognize', this._beginPanGesture.bind(this));
+ this._panGesture.connect('pan-update', this._updatePanGesture.bind(this));
+ this._panGesture.connect('end', this._endPanGesture.bind(this));
+ this._panGesture.connect('cancel', this._cancelPanGesture.bind(this));
+ this.bind_property('enabled', this._panGesture, 'enabled', 0);
+ this.bind_property_full('orientation',
+ this._panGesture, 'pan-axis',
+ GObject.BindingFlags.SYNC_CREATE,
+ (bind, source) => [
+ true,
+ source === Clutter.Orientation.HORIZONTAL
+ ? Clutter.PanAxis.X : Clutter.PanAxis.Y,
+ ],
+ null);
+ actor.add_action_full("SwipeTracker", Clutter.EventPhase.BUBBLE, this._panGesture);
+
this._touchpadGesture = new TouchpadSwipeGesture(allowedModes);
- this._touchpadGesture.connect('begin', this._beginGesture.bind(this));
- this._touchpadGesture.connect('update', this._updateGesture.bind(this));
+ this._touchpadGesture.connect('begin', this._beginTouchpadGesture.bind(this));
+ this._touchpadGesture.connect('update', this._updateTouchpadGesture.bind(this));
this._touchpadGesture.connect('end', this._endTouchpadGesture.bind(this));
this.bind_property('enabled', this._touchpadGesture, 'enabled', 0);
this.bind_property('orientation', this._touchpadGesture, 'orientation',
GObject.BindingFlags.SYNC_CREATE);
- this._touchGesture = new TouchSwipeGesture(allowedModes,
- GESTURE_FINGER_COUNT,
- Clutter.GestureTriggerEdge.AFTER);
- this._touchGesture.connect('begin', this._beginTouchSwipe.bind(this));
- this._touchGesture.connect('update', this._updateGesture.bind(this));
- this._touchGesture.connect('end', this._endTouchGesture.bind(this));
- this._touchGesture.connect('cancel', this._cancelTouchGesture.bind(this));
- this.bind_property('enabled', this._touchGesture, 'enabled', 0);
- this.bind_property('orientation', this._touchGesture, 'orientation',
- GObject.BindingFlags.SYNC_CREATE);
- this.bind_property('distance', this._touchGesture, 'distance', 0);
- global.stage.add_action_full('swipe', Clutter.EventPhase.CAPTURE, this._touchGesture);
-
- if (params.allowDrag) {
- this._dragGesture = new TouchSwipeGesture(allowedModes, 1,
- Clutter.GestureTriggerEdge.AFTER);
- this._dragGesture.connect('begin', this._beginGesture.bind(this));
- this._dragGesture.connect('update', this._updateGesture.bind(this));
- this._dragGesture.connect('end', this._endTouchGesture.bind(this));
- this._dragGesture.connect('cancel', this._cancelTouchGesture.bind(this));
- this.bind_property('enabled', this._dragGesture, 'enabled', 0);
- this.bind_property('orientation', this._dragGesture, 'orientation',
- GObject.BindingFlags.SYNC_CREATE);
- this.bind_property('distance', this._dragGesture, 'distance', 0);
- actor.add_action_full('drag', Clutter.EventPhase.CAPTURE, this._dragGesture);
- } else {
- this._dragGesture = null;
- }
-
if (params.allowScroll) {
this._scrollGesture = new ScrollGesture(actor, allowedModes);
- this._scrollGesture.connect('begin', this._beginGesture.bind(this));
- this._scrollGesture.connect('update', this._updateGesture.bind(this));
+ this._scrollGesture.connect('begin', this._beginTouchpadGesture.bind(this));
+ this._scrollGesture.connect('update', this._updateTouchpadGesture.bind(this));
this._scrollGesture.connect('end', this._endTouchpadGesture.bind(this));
this.bind_property('enabled', this._scrollGesture, 'enabled', 0);
this.bind_property('orientation', this._scrollGesture, 'orientation',
_interrupt() {
this.emit('end', 0, this._cancelProgress);
+ this._panGesture.cancel();
this._reset();
}
- _beginTouchSwipe(gesture, time, x, y) {
- if (this._dragGesture)
- this._dragGesture.cancel();
-
- this._beginGesture(gesture, time, x, y);
- }
-
- _beginGesture(gesture, time, x, y) {
+ _beginGesture(x, y) {
if (this._state === State.SCROLLING)
return;
- this._history.append(time, 0);
-
const rect = new Mtk.Rectangle({x, y, width: 1, height: 1});
let monitor = global.display.get_monitor_index_for_rect(rect);
this.emit('begin', monitor);
}
+ _beginPanGesture(panGesture) {
+ const coords = panGesture.get_begin_centroid();
+
+ this._beginGesture(coords.x, coords.y);
+ }
+
+ _beginTouchpadGesture(gesture, time, x, y) {
+ this._history.append(time, 0);
+
+ this._beginGesture(x, y);
+ }
+
_findClosestPoint(pos) {
const distances = this._snapPoints.map(x => Math.abs(x - pos));
const min = Math.min(...distances);
return [this._snapPoints[lowerIndex], this._snapPoints[upperIndex]];
}
- _updateGesture(gesture, time, delta, distance) {
+ _updateGesture(delta, distance) {
if (this._state !== State.SCROLLING)
return;
- if ((this._allowedModes & Main.actionMode) === 0 || !this.enabled) {
- this._interrupt();
- return;
- }
-
if (this.orientation === Clutter.Orientation.HORIZONTAL &&
Clutter.get_default_text_direction() === Clutter.TextDirection.RTL)
delta = -delta;
this._progress += delta / distance;
- this._history.append(time, delta);
this._progress = Math.clamp(this._progress, ...this._getBounds(this._initialProgress));
this.emit('update', this._progress);
}
+ _updatePanGesture(panGesture) {
+ const deltaVec = panGesture.get_delta();
+ const delta = this.orientation === Clutter.Orientation.HORIZONTAL
+ ? -deltaVec.get_x()
+ : -deltaVec.get_y();
+
+ this._updateGesture(delta, this._distance);
+ }
+
+ _updateTouchpadGesture(gesture, time, delta, distance) {
+ if ((this._allowedModes & Main.actionMode) === 0 || !this.enabled) {
+ this._interrupt();
+ return;
+ }
+
+ this._history.append(time, delta);
+ this._updateGesture(delta, distance);
+ }
+
_getEndProgress(velocity, distance, isTouchpad) {
if (this._cancelled)
return this._cancelProgress;
return this._snapPoints[index];
}
- _endTouchGesture(_gesture, time, distance) {
- this._endGesture(time, distance, false);
- }
-
- _endTouchpadGesture(_gesture, time, distance) {
- this._endGesture(time, distance, true);
- }
-
- _endGesture(time, distance, isTouchpad) {
+ _endGesture(velocity, distance, isTouchpad) {
if (this._state !== State.SCROLLING)
return;
return;
}
- this._history.trim(time);
-
- let velocity = this._history.calculateVelocity();
const endProgress = this._getEndProgress(velocity, distance, isTouchpad);
velocity /= distance;
this.emit('end', duration, endProgress);
}
- _cancelTouchGesture(_gesture, time, distance) {
+ _endPanGesture(panGesture) {
+ const velocity = panGesture.get_velocity();
+ const v = this.orientation === Clutter.Orientation.HORIZONTAL
+ ? -velocity.get_x()
+ : -velocity.get_y();
+
+ this._endGesture(v, this._distance, false);
+ }
+
+ _endTouchpadGesture(gesture, time, distance) {
+ if ((this._allowedModes & Main.actionMode) === 0 || !this.enabled) {
+ this._interrupt();
+ return;
+ }
+
+ this._history.trim(time);
+ const velocity = this._history.calculateVelocity();
+
+ this._endGesture(velocity, distance, true);
+ }
+
+ _cancelPanGesture() {
if (this._state !== State.SCROLLING)
return;
this._cancelled = true;
- this._endGesture(time, distance, false);
+ this._endGesture(0, this._distance, false);
}
/**
delete this._touchpadGesture;
}
- if (this._touchGesture) {
- global.stage.remove_action(this._touchGesture);
- delete this._touchGesture;
+ if (this._panGesture) {
+ this._panGesture.actor?.remove_action(this._panGesture);
+ delete this._panGesture;
}
}
});